package com.platform.utils.uuid;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class UuidGenUtils {
	
	private static int currVal = 0;
	
	private static final int maxValLen4 = 9999;
	
	private static final int maxValLen5 = 99999;
	
	private static Lock lock = new ReentrantLock();

	/**
	 * 获取32位唯一id
	 * @return
	 */
	public static String genOrderId() {

		StringBuffer uuid = new StringBuffer("PC");
		uuid.append(new SimpleDateFormat("yyMMddHHmmssSSS").format(new Date()));
		uuid.append(getRandomString(3));
		int val = getNextForLen4();
		uuid.append(addZeroLeft(String.valueOf(val), 4));

		return uuid.toString();
	}
	
	/**
	 * 获取32位唯一id
	 * @return
	 */
	public static String get20UUID() {
		
		StringBuffer uuid = new StringBuffer(new SimpleDateFormat("yyMMddHHmmssSSS").format(new Date()));
		uuid.append(getRandomString(3));
		int val = getNextForLen4();
		uuid.append(addZeroLeft(String.valueOf(val), 4));
		
		return uuid.toString();
	}
	
	public static String get32UUID() {
		
		StringBuffer uuid = new StringBuffer("");
		uuid.append(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()));
		uuid.append(getRandomString(10));
		int val = getNextForLen5();
		uuid.append(addZeroLeft(String.valueOf(val), 5));
		
		return uuid.toString();
	}
	
	/**
	 * 去下一个累计值（有锁）
	 * @return
	 */
	private static int getNextForLen4() {
		
		try {
			lock.lock();
			if (currVal < maxValLen4) {
				return ++currVal;
			}
			currVal = 1;
			return 1;
		} finally {
			lock.unlock();
		}	
	}
	/**
	 * 去下一个累计值（有锁）
	 * @return
	 */
	private static int getNextForLen5() {
		
		try {
			lock.lock();
			if (currVal < maxValLen5) {
				return ++currVal;
			}
			currVal = 1;
			return 1;
		} finally {
			lock.unlock();
		}	
	}

	/**
	 * 获取指定长度的随机数
	 * @param len
	 * @return
	 */
	public static String getRandomString(int len){
		StringBuffer sb = new StringBuffer("");
		Random r = new Random();
		for(int i = 0; i < len; i++){
			sb.append(Math.abs(r.nextInt()%10));
		}
		return sb.toString();
	}
	
	/**
	 * 指定长度 左补零
	 * @param value
	 * @param len
	 * @return
	 */
	public static String addZeroLeft(String value, int len){
		
		if(null == value){
			value = "";
		}
		if(value.length() >= len){
			return value.substring(0, len);
		}
		
		StringBuffer sb = new StringBuffer("");
		for(int i = value.length(); i < len; i++){
			sb.append("0");
		}
		sb.append(value);
		return sb.toString();
	}


	private static boolean IS_THREADLOCALRANDOM_AVAILABLE = false;
	private static Random random;
	private static final long leastSigBits;
	private static long lastTime;

	static {
		try {
			IS_THREADLOCALRANDOM_AVAILABLE = null != UuidGenUtils.class.getClassLoader().loadClass(
					"java.util.concurrent.ThreadLocalRandom");
		} catch (ClassNotFoundException e) {
		}

		byte[] seed = new SecureRandom().generateSeed(8);
		leastSigBits = new BigInteger(seed).longValue();
		if (!IS_THREADLOCALRANDOM_AVAILABLE) {
			random = new Random(leastSigBits);
		}
	}
	/**
	 * Create a new random UUID.
	 *
	 * @return the new UUID
	 */
	public static String random() {
		byte[] randomBytes = new byte[16];
		if (IS_THREADLOCALRANDOM_AVAILABLE) {
			java.util.concurrent.ThreadLocalRandom.current().nextBytes(randomBytes);
		} else {
			random.nextBytes(randomBytes);
		}

		long mostSigBits = 0;
		for (int i = 0; i < 8; i++) {
			mostSigBits = (mostSigBits << 8) | (randomBytes[i] & 0xff);
		}
		long leastSigBits = 0;
		for (int i = 8; i < 16; i++) {
			leastSigBits = (leastSigBits << 8) | (randomBytes[i] & 0xff);
		}

		return new UUID(mostSigBits, leastSigBits).toString().replaceAll("-", "");
	}

	/**
	 * Create a new time-based UUID.
	 *
	 * @return the new UUID
	 */
	public static String create() {
		long timeMillis = (System.currentTimeMillis() * 10000) + 0x01B21DD213814000L;

		lock.lock();
		try {
			if (timeMillis > lastTime) {
				lastTime = timeMillis;
			} else {
				timeMillis = ++lastTime;
			}
		} finally {
			lock.unlock();
		}

		// time low
		long mostSigBits = timeMillis << 32;

		// time mid
		mostSigBits |= (timeMillis & 0xFFFF00000000L) >> 16;

		// time hi and version
		mostSigBits |= 0x1000 | ((timeMillis >> 48) & 0x0FFF); // version 1

		return new UUID(mostSigBits, leastSigBits).toString().replaceAll("-", "");
	}
}

